"""线程池：
    线程， 进程 都是稀缺资源，不该被频繁的 创建，销毁
    架构解耦，线程创建 和 业务处理解耦， 更加优雅
    线程池是主流， 一般都是合理使用线程池， 是最佳实践

    1. 存放多个任务处理线程
    2. 负责多个线程的启停
    3. 管理向线程池提交的任务， 下发给线程去执行
"""



import threading
from queue import ThreadSafeQueue
from Task import AsyncTask, Task


class PrecessThread(threading.Thread):
    """
        任务处理线程
    """

    def __init__(self, task_queue: ThreadSafeQueue, *args, **kwargs):
        # 调用父类的构造函数
        super().__init__(*args, **kwargs)
        # 还需要一个标记，标记任务线程什么时候停止(事件对象)
        self.dismiss_flag = threading.Event()
        # 任务队列
        self.task_queue = task_queue
        self.args = args
        self.kwargs = kwargs


    def run(self):
        while True:
            # 判断线程是否停止
            if self.dismiss_flag.is_set():
                break

            task = self.task_queue.pop()
            if not isinstance(task, Task):
                continue
            
            # 执行task 实际逻辑， 传入相应参数
            result = task.callable(*task.args, **task.kwargs)   
            # 如果任务是 异步任务，将结果 加入到 对象的属性里去
            if isinstance(task, AsyncTask):
                task.set_result(result)
    
    
    def dismiss(self):
        self.dismiss_flag.set()
    
    def stop(self):
        self.dismiss()


class TaskTypeErrorException(Exception):
    pass


class ThreadPool():

    def __init__(self, size = 0):
        # 若没有， 默认约定线程池的大小为 cpu核数的 二倍
        if not size:
            size = 5
        # 线程池
        self.pool = ThreadSafeQueue(size)
        # 任务队列
        self.task_queue = ThreadSafeQueue()
        # 添加线程
        for i in range(size):
            self.pool.put(PrecessThread(self.task_queue)) # 将任务队列传入

    def start(self):
        """ 启动线程池里的所有线程 """
        for i in range(self.pool.size()):
            thread = self.pool.get(i)
            thread.start()
    
    def join(self):
        """ 停止线程池 """
        for i in range(self.pool.size()):
            thread = self.pool.get(i)
            thread.stop()
        
        # 清空线程池
        while self.pool.size():
            thread = self.pool.pop()
            thread.join()


    def put(self, item):
        """ 往线程池， 提交任务 """
        if not isinstance(item, Task):
            raise TaskTypeErrorException
        self.task_queue.put(item)


    def batch_put(self, item_list):
        if not isinstance(item_list, list):
            item_list = list(item_list)
        
        for item in item_list:
            self.task_queue.put(item)


    def size(self):
        return self.pool.size()


